home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Meeting Pearls 2
/
Meeting Pearls Vol. II (1995)(GTI - Schatztruhe)[!].iso
/
Pearls
/
psion
/
src.doc
/
unsorted
/
opl_c
/
readme.txt
< prev
Wrap
Text File
|
1984-10-28
|
4KB
|
139 lines
CALLING C FROM OPL
==================
There are essentially three ways to call C code from OPL:
a) Load the code into memory and execute it using the OPL keyword
USR.
b) Build the code into a DYL (dynamic link library). Load it
using the LibLoad OS call. Create the objects using the
LibCreateByHandle OS call. Then send messages to the created
objects using the LibSend OS call.
c) Build the code into a logical device driver (LDD). Load it
using the DevLoadLDDusing OS call. Open a channel to the device
using the OPL keyword IOOPEN. Execute the code using the OPL
keywords IOW and IOA.
This document describes the first method. This is the least flexible
of the three, however it is the easiest to get going.
There are two stages to the process. First you must produce a binary
file containing the code to be executed. Then you must load the code
in your OPL module and execute it.
Producing the binary executable file
------------------------------------
It is a straightforward process to produce the binary executable.
You write your C module and then compile it in the normal manner.
You must then link it, but without a startup module. Unfortunately I
have not yet worked out the runes to do this using the JPI linker,
however it is easy to do it using the Turbo linker, just type
TLINK <filename>
NOTE: when you link your C program you will get a NO STACK
warning, this is fine, since you stack will be provided by the OPL
program (SYS$PRGO to be precise)
Finally you use EXE2BIN to convert the .EXE file to a .BIN file.
There are, however some provisos:
Firstly the procedure to be called from OPL must return with a RETF
(ret far) instruction, this is accomplished using the JPI pragma:
#pragma call(seg_name=>null,near_call=>off)
Secondly, your module must not contain any static data. That is to
say any data used by you program must either be on the stack, be
allocated using p_alloc(), or have been reserved for you by the
calling OPL program. Note that this also means YOU MAY NOT HAVE ANY
QUOTED STRINGS (ie "Hello World"). This is because in an OPL program
DS points to the OPL's data segment (the data segment of SYS$PRGO to
be precise), and so any static data will be inaccessible.
Thirdly, although you know the address of the first procedure in the
module, you will not know the address of any of the other procedures.
I therefore suggest that, if you wish to call more than one
procedure, the first procedure should contain a switch statement
selecting which procedure to run:
#pragma save
#pragma call(seg_name=>null,near_call=>off)
GLDEF_C INT select(INT procno,INT p1,INT p2,INT p3)
/*
Must return with a retf (ret far), since called from OPL
*/
{
switch (procno)
{
case 1:
return (f1(p1,p2,p3));
case 2:
return (f2(p1,p2,p3));
}
return (-1);
}
#pragma restore
Note that USR passes (up to) 4 parameters to the called code, they
are in AX..DX which is where the JPI compiler expects to find them
(see the reg_params pragma in OPL.C).
OPL.C is a full working example of a C program that can be called
from OPL.
Loading the binary executable from OPL
--------------------------------------
There are three steps:
Firstly reserve some memory in which to load the code, this is most
easily done by declaring an array of the appropriate size.
Secondly load the binary file (produced above) into this array.
Thirdly use USR to execute the code.
All the above are illustrated in the file CALLC.OPL.
P_STD.H
-------
For those of you who do not have the Psion SDK here is an extract
that should allow you to compile OPL.C
#define P_STD_H
#define GLREF_D extern
#define GLDEF_D
#define LOCAL_D static
#define GLREF_C extern
#define LOCAL_C static
#define GLDEF_C
#define FOREVER for(;;)
#define TRUE 1
#define FALSE 0
#define NULL 0
#define VOID void
#define FAST register
typedef int INT,HANDLE;
typedef unsigned int UINT;
typedef signed char BYTE;
typedef unsigned char UBYTE;
typedef short int WORD;
typedef unsigned short int UWORD;
typedef long int LONG;
typedef unsigned long int ULONG;
typedef double DOUBLE;
typedef float FLOAT;
typedef unsigned char TEXT;
END OF DOCUMENT